/******************************************************************************
*  COPYRIGHT MorningCore CO.,LTD
******************************************************************************/

/*****************************************************************
 * FileName::    RSGen.c
 * version::     1.0.0
 * Purpose:      Cyclic shifted sequence generation for DMRS, SRS and PUCCH
 * Authors:      zhangshanzhong, 2008-12-18
 * Notes:        None
 ******************************************************************/

/******************************************************************************
*  HISTORY OF CHANGES
*   <Date>          <Author>        <Version>       <DESCRIPTION>
*   2008-12-18      zhangshanzhong  V1.0.0           original
*   2009-11-2       zhangyanan      V1.0.1           Modify bug of RB_Num=1,2
******************************************************************************/

/******************************************************************************
*  INCLUDE FILES
******************************************************************************/
#include "../head/ue_tx_rsgen_f.h"

/*****************************************************************************
* Function: RSGen()
* Purpose:  This function performs cyclic shift sequence generation for DMRS, SRS
*           and PUCCH
*
* Relation:
            Calls       : ....
            Called by   : ....
* Params:
*   <Name>                  <Type>      <In/Out>    <Description>
*   ZCRootSeqGen_Op[1320]   cmplx_frN   In          Zadoff-Chu root sequence
*   RootSeqLen              int         In          length of root seq
*   RS_SC_Num               int         In          number of sub-carriers of RS
*   Ncs                     int         In          Cyclic shift param in 3GPP TS 38.211
*   uIdx                  int         In          Sequence index for short base seq
*   SRS_Flag                int         In          whether SRS flag
*   N_RotateCoef            int8        In          processing bit width
*   RSGen_Op[1320]          cmplx_frN   Out         output of RSGen
* Return:  void
* Note:    None
*******************************************************************************/
void RSGen_f_ReleaseFlag
(
    IN int      UL_RB_Num,                  // number of sub-carriers of RS
    IN int      Ncs,                        // Cyclic shift param in 3GPP TS 38.211
    IN int      Omiga,                      // Omiga in 3GPP TS 38.211
    IN int      Delta,                      // Delta in 3GPP TS 38.211
    IN int      uIdx,                       // u in 3GPP TS 38.211
    IN int      vIdx,                       // v in 3GPP TS 38.211
    IN int      RS_Type,             // alpha = 2*pi*Ncs/12 for 0; alpha = 2*pi*Ncs/8 for 1
    OUT cmplx_t RSGen_Op[]           // output of RSGen
)
{
    /*variables definition*/
    cmplx_t BaseSeq[MAXRBNUM * 12]; // base sequence Q(N,1)
    double DividParam; // input dividend parameter
    cmplx_t CS_Param; // Cyclic shift parameter
    cmplx_t ZCRootSeqGen_Op[MAXRBNUM * 12]; // Zadoff-Chu root sequence
    int     RS_SC_Num = 0;      // Rs length
    cmplx_t temp;
    int i; // loop index
    int16 divisor;
    int  RootSeqParam = 0;  // u (PRACH) or q (RS) in 3GPP TS 38.211
    double RootSeqParamTemp; // for calc u
    int   RootSeqLen = 0;                   // length of root seq
    int BsSeqTable = 0;

    /*Function body*/
    // RS length
    RS_SC_Num = (int)(UL_RB_Num * 12 / pow(2.0, Delta));

    // determine base sequence according to length
    if (RS_SC_Num >= 30) // Sequence length >= 30
    {
        // update RootSeqLen according to UL_RB_Num
        if (0 == Delta) // 0
        {
            RootSeqLen = PrimTable_Delta0[UL_RB_Num - 1];
        }
        else if (1 == Delta) // 1
        {
            RootSeqLen = PrimTable_Delta1[UL_RB_Num - 1];
        }
        else // 2
        {
            RootSeqLen = PrimTable_Delta2[UL_RB_Num - 1];
        }

        if (30 == RS_SC_Num) // q*(n+1)*(n+2)/31, q = u + 1
        {
            RootSeqParam = uIdx + 1; // q
            RootSeqLen = 31;

            for (i = 0; i < RootSeqLen; i++)
            {
                DividParam = (RootSeqParam * ((i + 1) * (i + 2) % (2 * RootSeqLen)) % (2 * RootSeqLen));

                temp.re = (double)cos(PI_FLTP * DividParam / RootSeqLen);
                temp.im = - (double)sin(PI_FLTP * DividParam / RootSeqLen);

                // write to output
                ZCRootSeqGen_Op[i] = temp;
            }
        }
        else // q*n*(n+1)/RootSeqLen
        {
            RootSeqParamTemp = (double)(RootSeqLen * (uIdx + 1) / 31.0);
            RootSeqParam = (int)((int)(RootSeqParamTemp + 0.5) + vIdx * pow(-1.0, (int)(2 * RootSeqParamTemp))); // q

            // ZC generation
            ZCRootSeqGen_f
            (
                RootSeqLen,   // 839 or 139 only for PRACH
                RootSeqParam, // u (PRACH) or q (RS) in 3GPP TS 38.211
                ZCRootSeqGen_Op // Zadoff-Chu root sequence
            );
        }

        // base sequence
        for (i = 0; i < RS_SC_Num; i++)
        {
            BaseSeq[i] = ZCRootSeqGen_Op[i % RootSeqLen];
        }
    }
    else // Sequence length < 30
    {
        for (i = 0; i < RS_SC_Num; i++)
        {
            // get BsSeqTable according to RS_SC_Num
            if (6 == RS_SC_Num) // 6
            {
                BsSeqTable = BsSeqTable6[uIdx][i];
            }
            else if (12 == RS_SC_Num) // 12
            {
                BsSeqTable = BsSeqTable12_V201806[uIdx][i];
            }
            else if (18 == RS_SC_Num) // 18
            {
                BsSeqTable = BsSeqTable18_V201806[uIdx][i];
            }
            else // SCNumPerRB*2
            {
                BsSeqTable = BsSeqTable24_V201806[uIdx][i];
            }

            // get complex value
            if (BsSeqTable == -1)
            {
                BaseSeq[i].re = (double)sqrt(2.0) / 2;
                BaseSeq[i].im = -(double)sqrt(2.0) / 2;
            }
            else if (BsSeqTable == 1)
            {
                BaseSeq[i].re = (double)sqrt(2.0) / 2;
                BaseSeq[i].im = (double)sqrt(2.0) / 2;
            }
            else if (BsSeqTable == 3)
            {
                BaseSeq[i].re = -(double)sqrt(2.0) / 2;
                BaseSeq[i].im = (double)sqrt(2.0) / 2;
            }
            else if (BsSeqTable == -3)
            {
                BaseSeq[i].re = -(double)sqrt(2.0) / 2;
                BaseSeq[i].im = -(double)sqrt(2.0) / 2;
            }
        }
    }

    // determine cyclic shifted output sequence according to RS_Type
    if (RS_Type == 0) // 12
    {
        divisor = 12;
    }
    else if (RS_Type == 1) // 8
    {
        divisor = 8;
    }
    else
    {
        printf("Error Configuration for SRS flag!");
    }

    // cyclic shift
    //if(RS_Type == 1)
    {
        for (i = 0; i < RS_SC_Num; i++)
        {
            // Mod, alpha
            DividParam = (double)((Ncs * i) % divisor);

            // determine CS param alpha
            CS_Param.re = (double)cos(2 * PI_FLTP * DividParam / divisor);
            CS_Param.im = (double)sin(2 * PI_FLTP * DividParam / divisor);

            // shift according to alpha
            RSGen_Op[i] = cmlt_f(CS_Param, BaseSeq[i]);
        }
    }
}
/*----------- function definition-----------------------------------*/
/*****************************************************************************
* Function: ZCRootSeqGen()
* Purpose:  This function performs Zadoff-Chu root sequence generation for base
*           sequence generation for RS and preamble sequence for PRACH.
*
* Relation:
            Calls       : RotateCoefGen()
            Called by   : ...
* Params:
*   <Name>                  <Type>      <In/Out>    <Description>
*   RootSeqLen              int         In          Root sequence length
*   RootSeqParam            int         In          Sequence index
*   N_RotateCoef            int8        In          processing bit width
*   ZCRootSeqGen_Op[1320]   cmplx_frN   Out         Output ZC root sequence Q(16,1)
* Return:  void
* Note:    <the limitations to use this function or other comments>
*******************************************************************************/
void ZCRootSeqGen_f
(
    IN int      RootSeqLen,   // 839 or 139 only for PRACH
    IN int      RootSeqParam, // u (PRACH) or q (RS) in 3GPP TS 38.211
    OUT cmplx_t  ZCRootSeqGen_Op[] // Zadoff-Chu root sequence
)
{
    /*variables definition*/
    int i; // loop index
    uint32 DividParam; // input dividend parameter //modified by shanshan 20100624
    int16 divisor;  // divisor of input
    cmplx_t temp; //

    /*Init*/

    // root sequence length as divisor
    divisor = RootSeqLen;

    /*Function body*/
    for (i = 0; i < RootSeqLen; i++)
    {
        // deleted by shanshan @20180604
        //DividParam = RootSeqParam * i * (i+1);
        // added by shanshan @20180604
        DividParam = (RootSeqParam * (i * (i + 1) % (2 * RootSeqLen)) % (2 * RootSeqLen));
        // ended by shanshan @20180604

        temp.re = (double)cos(PI_FLTP * DividParam / RootSeqLen);
        temp.im = - (double)sin(PI_FLTP * DividParam / RootSeqLen);

        // write to output
        ZCRootSeqGen_Op[i] = temp;
    }
}



